package ar.edu.itba.it.pdc.httpParser;

import java.util.LinkedList;
import java.util.List;

import ar.edu.itba.it.pdc.httpParser.exceptions.HttpBadRequestException;
import ar.edu.itba.it.pdc.httpParser.exceptions.HttpMethodNotSuportedException;
import ar.edu.itba.it.pdc.httpParser.exceptions.HttpVersionNotSuportedException;
import ar.edu.itba.it.pdc.httpParser.interfaces.Parser;
import ar.edu.itba.it.pdc.httpParser.models.HttpStatusLine;
import ar.edu.itba.it.pdc.httpParser.models.HttpVersion;
import ar.edu.itba.it.pdc.httpParser.models.Token;
import ar.edu.itba.it.pdc.httpParser.models.TokenType;


public class StatusLineParser implements Parser {

	private enum State {
		PROTOCOL, PROTOCOLEND, VERSION, VERSIONEND, STATUSCODE, STATUSCODEEND, STATUSDESC};

	private State state = State.PROTOCOL;
	
	HttpStatusLine model = new HttpStatusLine();
	
	private List<Token> statusDesc = new LinkedList<Token>();

	@Override
	public int parseToken(Token token)
			throws HttpMethodNotSuportedException, HttpBadRequestException,
			HttpVersionNotSuportedException {
		switch (state) {
		
			case STATUSCODE:
				
				if (token.isType(TokenType.WORD)) {
					if (token.isNumber()) {
						model.setStatusCode(token);
						state = State.STATUSCODEEND;
					} else {
						throw new HttpBadRequestException(token);
					}
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
	
			case STATUSDESC:
				
				if (token.isType(TokenType.WORD) || token.isType(TokenType.SPACE)) {
					statusDesc.add(token);
				} else if(token.isType(TokenType.CRLF)){
					model.setStatusDesc(statusDesc);
					return 0;
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
	
			case PROTOCOL:
				
				if (token.isType(TokenType.WORD) && token.is("HTTP")) {
					state = State.PROTOCOLEND;
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
	
			case VERSION:
				
				if (token.isType(TokenType.WORD)) {
					if (token.is("1.0")) {
						model.setVersion(HttpVersion.ONE);
						state = State.VERSIONEND;
					} else if (token.is("1.1")) {
						model.setVersion(HttpVersion.ONEDOTONE);
						state = State.VERSIONEND;
					} else {
						throw new HttpVersionNotSuportedException();
					}
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
	
			case VERSIONEND:
			case STATUSCODEEND:
				
				if (token.isType(TokenType.SPACE)) {
					state = State.values()[state.ordinal() + 1];
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
	
			case PROTOCOLEND:
				
				if (token.isType(TokenType.DIVIDE)) {
					state = State.values()[state.ordinal() + 1];
				} else {
					throw new HttpBadRequestException(token);
				}
				break;
			}
			return -1;
	}

	public HttpStatusLine getModel(){
		return model;
	}

}
